/* init.c */
#include "stdio.h"
#include "shell.h"
#include "malloc.h"

#include "api/system.h"

static void showPartition(Partition *efp)
{
    printf("Partition(start=%p, head=%p)\n", efp, (Block *)(efp->head));
}

static void showBlock(Block *block)
{
    printf("Block(start=%p, end=%p, size=%d, previous=%p, next=%p)\n", block, (unsigned long)block + block->size - 1, block->size, block->previous, block->next);
}

void partitionWalkByAddr(unsigned long handler)
{
    Partition *partition = (Partition *)handler;
    showPartition(partition);
    Block *block = (Block *)(partition->head);
    while (block != 0)
    {
        showBlock(block);
        block = (Block *)block->next;
    }
    printf("\n");
}

int testCase1(int argc, char *argv[])
{
	//======for malloc===============================
	char *buf1 = (char *)malloc(19);
	char *buf2 = (char *)malloc(24);

	for (int i = 0; i < 17; i++)
		*(buf1 + i) = '*';
	*(buf1 + 17) = '\n';
	*(buf1 + 18) = '\000';

	for (int i = 0; i < 22; i++)
		*(buf2 + i) = '#';
	*(buf2 + 22) = '\n';
	*(buf2 + 23) = '\000';

	printf("\033[35mWe allocated 2 buffers.\n\033[0m");
	printf("\033[35mBUF1(size=19, addr=0x%x) filled with 17(*): \033[0m", (unsigned long)buf1);
	printf(buf1);
	printf("\033[35mBUF2(size=24, addr=0x%x) filled with 22(#): \033[0m", (unsigned long)buf2);
	printf(buf2);

	printf("\n");

	free((unsigned long)buf1);
	free((unsigned long)buf2);

	return 0;
}

int testCase2(int argc, char *argv[])
{
	//======for malloc===============================
	char *buf1 = (char *)malloc(11);
	char *buf2 = (char *)malloc(21);

	for (int i = 0; i < 9; i++)
		*(buf1 + i) = '+';
	*(buf1 + 9) = '\n';
	*(buf1 + 10) = '\000';

	for (int i = 0; i < 19; i++)
		*(buf2 + i) = ',';
	*(buf2 + 19) = '\n';
	*(buf2 + 20) = '\000';

	printf("\033[35mWe allocated 2 buffers.\n\033[0m");
	printf("\033[35mBUF1(size=9, addr=0x%x) filled with 9(+): \033[0m", (unsigned long)buf1);
	printf(buf1);
	printf("\033[35mBUF2(size=19, addr=0x%x) filled with 19(,): \033[0m", (unsigned long)buf2);
	printf(buf2);

	printf("\n");

	free((unsigned long)buf1);
	free((unsigned long)buf2);

	return 0;
}

int maxMallocSizeNow(int argc, char *argv[])
{
	int i = 0x1000;
	unsigned long x;

	while (1)
	{
		x = malloc(i);
		if (x)
			free(x);
		else
			break;

		i += 0x1000;
	}
	printf("MAX_MALLOC_SIZE: 0x%x (with step = 0x1000);\n", i);
}

//======for dPartition===============================
int testdP1(int argc, char *argv[])
{
	unsigned long x, x1, xHandler;
	int i, tsize = 0x100;
	x = malloc(tsize);
	if (x)
	{
		printf("We had successfully ");
		printf("\033[35mmalloc()\033[0m");
		printf(" a small memBlock (size=0x%x, addr=0x%x);\n", tsize, x);

		printf("It is initialized as a very small dPartition;\n");
		xHandler = dPartitionInit(x, tsize);
		partitionWalkByAddr(x);

		i = 0x10;
		while (1)
		{
			x1 = dPartitionAlloc(xHandler, i);
			printf("Alloc a memBlock with size 0x%x, ", i);
			if (x1)
			{
				printf("\033[35msuccess(addr=0x%x)!\033[0m", x1);
				dPartitionFree(xHandler, x1);
				printf("......Relaesed;\n");
			}
			else
			{
				printf("\033[35mfailed!\n\033[0m");
				break;
			}

			i <<= 1;
		}

		printf("Now, converse the sequence.\n");
		while (i >= 0x10)
		{
			x1 = dPartitionAlloc(xHandler, i);
			printf("Alloc a memBlock with size 0x%x, ", i);
			if (x1)
			{
				printf("\033[35msuccess(addr=0x%x)!\033[0m", x1);
				dPartitionFree(xHandler, x1);
				printf("......Relaesed;\n");
			}
			else
				printf("\033[35mfailed!\n\033[0m");

			i >>= 1;
		}

		free(x);
	}
	else
		printf("MALLOC FAILED, CAN't TEST dPartition\n");
}

int testdP2(int argc, char *argv[])
{
	unsigned long x, x1, x2, x3, xHandler;
	int i, tsize = 0x100;
	x = malloc(tsize);
	if (x)
	{
		printf("We had successfully ");
		printf("\033[35mmalloc()\033[0m");
		printf(" a small memBlock (size=0x%x, addr=0x%x);\n", tsize, x);

		printf("It is initialized as a very small dPartition;\n");
		xHandler = dPartitionInit(x, tsize);
		partitionWalkByAddr(x);

		printf("Now, A:B:C:- ==> -:B:C:- ==> -:C- ==> - .\n");

		x1 = dPartitionAlloc(xHandler, 0x10);
		printf("Alloc memBlock A with size 0x10: ");
		if (x1)
			printf("\033[35msuccess(addr=0x%x)!\n\033[0m", x1);
		else
			printf("\033[35mfailed!\n\033[0m");
		*(unsigned long *)x1 = 0xAAAAAAAA;
		partitionWalkByAddr(xHandler);

		x2 = dPartitionAlloc(xHandler, 0x20);
		printf("Alloc memBlock B with size 0x20: ");
		if (x2)
			printf("\033[35msuccess(addr=0x%x)!\n\033[0m", x2);
		else
			printf("\033[35mfailed!\n\033[0m");
		*(unsigned long *)x2 = 0xBBBBBBBB;
		partitionWalkByAddr(xHandler);

		x3 = dPartitionAlloc(xHandler, 0x30);
		printf("Alloc memBlock C with size 0x30: ");
		if (x3)
			printf("\033[35msuccess(addr=0x%x)!\n\033[0m", x3);
		else
			printf("\033[35mfailed!\n\033[0m");
		*(unsigned long *)x3 = 0xCCCCCCCC;
		partitionWalkByAddr(xHandler);

		printf("Now, release A.\n");
		dPartitionFree(xHandler, x1);
		partitionWalkByAddr(xHandler);

		printf("Now, release B.\n");
		dPartitionFree(xHandler, x2);
		partitionWalkByAddr(xHandler);

		printf("At last, release C.\n");
		dPartitionFree(xHandler, x3);
		partitionWalkByAddr(xHandler);

		free(x);
	}
	else
		printf("MALLOC FAILED, CAN't TEST dPartition\n");
}

int testdP3(int argc, char *argv[])
{
	unsigned long x, x1, x2, x3, xHandler;
	int i, tsize = 0x100;
	x = malloc(tsize);
	if (x)
	{
		printf("We had successfully ");
		printf("\033[35mmalloc()\033[0m");
		printf(" a small memBlock (size=0x%x, addr=0x%x);\n", tsize, x);

		printf("It is initialized as a very small dPartition;\n");
		xHandler = dPartitionInit(x, tsize);
		partitionWalkByAddr(x);

		printf("Now, A:B:C:- ==> A:B:- ==> A:- ==> - .\n");

		x1 = dPartitionAlloc(xHandler, 0x10);
		printf("Alloc memBlock A with size 0x10: ");
		if (x1)
			printf("\033[35msuccess(addr=0x%x)!\n\033[0m", x1);
		else
			printf("\033[35mfailed!\n\033[0m");
		*(unsigned long *)x1 = 0xAAAAAAAA;
		partitionWalkByAddr(xHandler);

		x2 = dPartitionAlloc(xHandler, 0x20);
		printf("Alloc memBlock B with size 0x20: ");
		if (x2)
			printf("\033[35msuccess(addr=0x%x)!\n\033[0m", x2);
		else
			printf("\033[35mfailed!\n\033[0m");
		*(unsigned long *)x2 = 0xBBBBBBBB;
		partitionWalkByAddr(xHandler);

		x3 = dPartitionAlloc(xHandler, 0x30);
		printf("Alloc memBlock C with size 0x30: ");
		if (x3)
			printf("\033[35msuccess(addr=0x%x)!\n\033[0m", x3);
		else
			printf("\033[35mfailed!\n\033[0m");
		*(unsigned long *)x3 = 0xCCCCCCCC;
		partitionWalkByAddr(xHandler);

		printf("Now, release C.\n");
		dPartitionFree(xHandler, x3);
		partitionWalkByAddr(xHandler);

		printf("Now, release B.\n");
		dPartitionFree(xHandler, x2);
		partitionWalkByAddr(xHandler);

		printf("At last, release A.\n");
		dPartitionFree(xHandler, x1);
		partitionWalkByAddr(xHandler);

		free(x);
	}
	else
		printf("MALLOC FAILED, CAN't TEST dPartition\n");
}

int testeFP(int argc, char *argv[])
{
	int i = 0x1000;
	unsigned long x, x1, x2, x3, x4, x5, xHandler;
	int psize = 31;
	int n = 4;
	int tsize;
	//======for eFPartition===============================
	tsize = eFPartitionTotalSize(psize, n);
	x = malloc(tsize);
	printf("X:0x%x:%d \n", x, tsize);
	if (x)
	{
		printf("We had successfully ");
		printf("\033[35mmalloc()\033[0m");
		printf(" a small memBlock (size=0x%x, addr=0x%x);\n", tsize, x);

		printf("It is initialized as a very small ePartition;\n");
		xHandler = eFPartitionInit(x, psize, n);

		partitionWalkByAddr(xHandler);

		x1 = eFPartitionAlloc(xHandler);
		if (x1)
		{
			*(unsigned long *)x1 = 0xAAAAAAAA;
			printf("Alloc memBlock A，start = 0x%x: 0x%x \n", x1, *(unsigned long *)x1);
		}
		else
			printf("Alloc memBlock A, failed!\n");
		partitionWalkByAddr(xHandler);

		x2 = eFPartitionAlloc(xHandler);
		if (x2)
		{
			*(unsigned long *)x2 = 0xBBBBBBBB;
			printf("Alloc memBlock B，start = 0x%x: 0x%x \n", x2, *(unsigned long *)x2);
		}
		else
			printf("Alloc memBlock B, failed!\n");
		partitionWalkByAddr(xHandler);

		x3 = eFPartitionAlloc(xHandler);
		if (x3)
		{
			*(unsigned long *)x3 = 0xCCCCCCCC;
			printf("Alloc memBlock C，start = 0x%x: 0x%x \n", x3, *(unsigned long *)x3);
		}
		else
			printf("Alloc memBlock C, failed!\n");
		partitionWalkByAddr(xHandler);

		x4 = eFPartitionAlloc(xHandler);
		if (x4)
		{
			*(unsigned long *)x4 = 0xDDDDDDDD;
			printf("Alloc memBlock D，start = 0x%x: 0x%x \n", x4, *(unsigned long *)x4);
		}
		else
			printf("Alloc memBlock D, failed!\n");
		partitionWalkByAddr(xHandler);

		x5 = eFPartitionAlloc(xHandler);
		if (x5)
		{
			*(unsigned long *)x5 = 0xEEEEEEEE;
			printf("Alloc memBlock E，start = 0x%x: 0x%x \n", x5, *(unsigned long *)x5);
		}
		else
			printf("Alloc memBlock E, failed!\n");
		partitionWalkByAddr(xHandler);

		printf("Now, release A.\n");
		eFPartitionFree(xHandler, x1);
		partitionWalkByAddr(xHandler);

		printf("Now, release B.\n");
		eFPartitionFree(xHandler, x2);
		partitionWalkByAddr(xHandler);

		printf("Now, release C.\n");
		eFPartitionFree(xHandler, x3);
		partitionWalkByAddr(xHandler);

		printf("Now, release D.\n");
		eFPartitionFree(xHandler, x4);
		partitionWalkByAddr(xHandler);
	}
	else
		printf("TSK2: MALLOC FAILED, CAN't TEST eFPartition\n");

	return 0;
}

void memTestCaseInit(void)
{
	addNewCmd("testMalloc1", "Malloc, write and read.", testCase1);
	addNewCmd("testMalloc2", "Malloc, write and read.", testCase2);
	addNewCmd("maxMallocSizeNow", "MAX_MALLOC_SIZE always changes. What's the value Now?", maxMallocSizeNow);

	addNewCmd("testdP1", "Init a dPatition(size=0x100). [Alloc,Free]* with step = 0x20", testdP1);
	addNewCmd("testdP2", "Init a dPatition(size=0x100). A:B:C:- ==> -:B:C:- ==> -:C:- ==> - .", testdP2);
	addNewCmd("testdP3", "Init a dPatition(size=0x100). A:B:C:- ==> A:B:- ==> A:- ==> - .", testdP3);
	addNewCmd("testeFP", "Init a eFPatition. Alloc all and Free all.", testeFP);
}
